﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using MathNet.Numerics.LinearAlgebra;
using Expr = MathNet.Symbolics.SymbolicExpression;

namespace NumericalAnalysis.DataInterpolation
{
    public static class NumericalExtension
    {

        #region vector tuple 等 数据结构转换和提取

        public static IList<Vector<double>> ToVector(this IEnumerable<Tuple<double, double>> _tuples)
        {
            List<Vector<double>> vectors = new List<Vector<double>>();
            foreach (var tuple in _tuples)
            {
                var vec = Vector<double>.Build.Dense(2);
                vec.Add(tuple.Item1);
                vec.Add(tuple.Item2);
                vectors.Add(vec);
            }
            return vectors;
        }

        public static IList<Vector<double>> ToVector(this IEnumerable<Tuple<double, double, double>> _tuples)
        {
            List<Vector<double>> vectors = new List<Vector<double>>();
            foreach (var tuple in _tuples)
            {
                var vec = Vector<double>.Build.Dense(3);
                vec.Add(tuple.Item1);
                vec.Add(tuple.Item2);
                vec.Add(tuple.Item3);
                vectors.Add(vec);
            }
            return vectors;
        }

        public static IList<Vector<double>> ToVector(this IEnumerable<Tuple<double, double, double, double>> _tuples)
        {
            List<Vector<double>> vectors = new List<Vector<double>>();
            foreach (var tuple in _tuples)
            {
                var vec = Vector<double>.Build.Dense(4);
                vec.Add(tuple.Item1);
                vec.Add(tuple.Item2);
                vec.Add(tuple.Item3);
                vec.Add(tuple.Item4);
                vectors.Add(vec);
            }
            return vectors;
        }



        public static IList<Tuple<double, double>> ToTuple2(this IEnumerable<Vector<double>> _vectors)
        {
            List<Tuple<double, double>> tuples = new List<Tuple<double, double>>();
            foreach (var vector in _vectors)
            {
                var v1 = vector[0];
                var v2 = vector[1];
                var tuple = new Tuple<double, double>(v1, v2);
                tuples.Add(tuple);
            }
            return tuples;
        }

        public static IList<Tuple<double, double, double>> ToTuple3(this IEnumerable<Vector<double>> _vectors)
        {
            List<Tuple<double, double, double>> tuples = new List<Tuple<double, double, double>>();
            foreach (var vector in _vectors)
            {
                var v1 = vector[0];
                var v2 = vector[1];
                var v3 = vector[2];
                var tuple = new Tuple<double, double, double>(v1, v2, v3);
                tuples.Add(tuple);
            }
            return tuples;
        }

        public static IList<Tuple<double, double, double, double>> ToTuple4(this IEnumerable<Vector<double>> _vectors)
        {
            int count = _vectors.First().Count();
            var tuples = new List<Tuple<double, double, double, double>>();
            foreach (var vector in _vectors)
            {
                var v1 = vector[0];
                var v2 = vector[1];
                var v3 = vector[2];
                var v4 = vector[3];
                var tuple = new Tuple<double, double, double, double>(v1, v2, v3, v4);
                tuples.Add(tuple);
            }
            return tuples;
        }



        public static IList<double> GetXs(this IEnumerable<Vector<double>> _vectors)
        {
            return _vectors.Select(v => v[0]).ToList();
        }

        public static IList<double> GetYs(this IEnumerable<Vector<double>> _vectors)
        {
            return _vectors.Select(v => v[1]).ToList();
        }

        public static IList<double> GetValsBy(this IEnumerable<Vector<double>> _vectors, int index)
        {
            return _vectors.Select(v => v[index]).ToList();
        }



        public static IList<double> GetXs(this IEnumerable<Tuple<double, double>> _tuples)
        {
            return _tuples.Select(v => v.Item1).ToList();
        }

        public static IList<double> GetYs(this IEnumerable<Tuple<double, double>> _tuples)
        {
            return _tuples.Select(v => v.Item2).ToList();
        }

        public static IList<double> GetXs(this IEnumerable<Tuple<double, double, double>> _tuples)
        {
            return _tuples.Select(v => v.Item1).ToList();
        }

        public static IList<double> GetYs(this IEnumerable<Tuple<double, double, double>> _tuples)
        {
            return _tuples.Select(v => v.Item2).ToList();
        }

        public static IList<double> GetZs(this IEnumerable<Tuple<double, double, double>> _tuples)
        {
            return _tuples.Select(v => v.Item3).ToList();
        }

        #endregion

        /// <summary>
        /// 检查一列数字是否等分  用于检查坐标等距
        /// </summary>
        /// <param name="xs"></param>
        /// <returns></returns>
        public static double IsEquidistance(this IEnumerable<double> xs)
        {
            var xsOrders = xs.OrderBy(x => x).ToList();
            double dis = (xsOrders.Last() - xsOrders.First()) / (xsOrders.Count - 1);
            for (int i = 0; i < xsOrders.Count - 1; i++)
            {
                bool isNeq = Math.Abs(xsOrders[i + 1] - xsOrders[i] - dis) > 0.001d;
                if (isNeq) return 0;
            }
            return dis;
        }

        #region  符号转化


        /// <summary>
        /// 式子的多阶导数
        /// </summary>
        /// <param name="exprStr">式子的字符串表达</param> 
        /// <param name="indexs">导数针对的变量  数量为阶数</param>
        /// <returns></returns>
        public static Expr DiffBy(this string exprStr, List<string> indexs)
        {
            Expr expr = Expr.Parse(exprStr);
            return expr.DiffBy(indexs);
        }

        /// <summary>
        /// 式子的多阶导数
        /// </summary>
        /// <param name="expr">式子 </param> 
        /// <param name="indexs">导数针对的变量  数量为阶数</param>
        /// <returns></returns>
        /// <returns></returns>
        public static Expr DiffBy(this Expr expr, List<string> indexs)
        {
            foreach (var index in indexs)
            {
                expr = expr.Differentiate(index);
            }
            return expr;
        }
         /// <summary>
        /// 式子的多阶导数
        /// </summary>
        /// <param name="expr">式子 </param> 
        /// <param name="indexs">导数针对的变量  数量为阶数</param>
        /// <returns></returns>
        /// <returns></returns>
        public static Expr DiffBy(this Expr expr, string varStr)
        {
            expr = expr.Differentiate(varStr); 
            return expr;
        }


        /// <summary>
        /// 将表达式转为方法 1元方程
        /// </summary>
        /// <param name="expr"></param>
        /// <param name="varStrs"></param>
        /// <returns></returns>
        public static Func<double, double> ToFunc1(this Expr expr, string varStr)
        {
            var exprFunc = expr.Compile(varStr);
            return exprFunc;
        }
        /// <summary>
        /// 将表达式转为方法 2元方程
        /// </summary>
        /// <param name="expr"></param>
        /// <param name="varStrs"></param>
        /// <returns></returns>
        public static Func<double, double, double> ToFunc2(this Expr expr, List<string> varStrs)
        {
            if (varStrs.Count == 2)
            {
                var exprFunc = expr.Compile(varStrs[0], varStrs[1]);
                return exprFunc;
            }
            else
            {
                return (x, y) => { return 0; };
            }
        }

        /// <summary>
        /// 将表达式转为方法 3元方程
        /// </summary>
        /// <param name="expr"></param>
        /// <param name="varStrs"></param>
        /// <returns></returns>
        public static Func<double, double, double, double> ToFunc3(this Expr expr, List<string> varStrs)
        {
            if (varStrs.Count == 3)
            {
                var exprFunc = expr.Compile(varStrs[0], varStrs[1], varStrs[2]);
                return exprFunc;
            }
            else
            {
                return (x, y, z) => { return 0; };
            }
        }

        /// <summary>
        /// 将表达式转为方法 4元方程
        /// </summary>
        /// <param name="expr"></param>
        /// <param name="varStrs"></param>
        /// <returns></returns>
        public static Func<double, double, double, double, double> ToFunc4(this Expr expr, List<string> varStrs)
        {
            if (varStrs.Count == 4)
            {
                var exprFunc = expr.Compile(varStrs[0], varStrs[1], varStrs[2], varStrs[3]);
                return exprFunc;
            }
            else
            {
                return (x, y, z, w) => { return 0; };
            }
        }

        #endregion


        /// <summary>
        ///  将所有点的变量值 带入式子  获得结果点集合
        /// </summary>
        /// <param name="expr"></param>
        /// <param name="varStr"></param>
        /// <param name="interpXs"></param>
        /// <returns></returns>
        public static IList<Tuple<double, double>> GeneratePointBy(this Expr expr, string varStr , IEnumerable<double> interpXs)
        {
            if (varStr == "") varStr = "t";
            var exprFunc = expr.ToFunc1(varStr);
            //计算方程上的点   
            List<Tuple<double, double>> interpPnts = interpXs
                .Select(xv => new Tuple<double, double>(xv, exprFunc(xv)))
                .ToList();
            //插值点数据集 
            return interpPnts;
        }
         
        /// <summary>
        /// 将所有点的变量值 带入式子  获得结果点集合
        /// </summary>
        /// <param name="expr"></param>
        /// <param name="_varStrs"></param>
        /// <param name="_interpXs"></param>
        /// <param name="_interpYs"></param>
        /// <returns></returns>
        public static IList<Tuple<double, double, double>> GeneratePointBy
            (this Expr expr, IEnumerable<string> _varStrs, IEnumerable<double> _interpXs, IEnumerable<double> _interpYs)
        {
            var  varStrs = _varStrs.ToList();
            var interpXs = _interpXs.ToList();
            var interpYs = _interpYs.ToList();
        
            if (varStrs.Count  == 0) varStrs.Add("t"); ;    
            var exprFunc = expr.ToFunc2(varStrs);

            List<Tuple<double, double, double>> interpPnts = new List<Tuple<double, double, double>>(); 
            //计算方程上的点   
            for (int i = 0; i < interpXs.Count(); i++)
            {
                var xx = interpXs[i];
                var yy = interpYs[i];
                var zz = exprFunc(interpXs[i], interpYs[i]);
                var tuple = new Tuple<double, double, double>(xx, yy,zz);
                interpPnts.Add(tuple); 
            }
            //插值点数据集 
            return interpPnts;
        }


    }
}
